package com.beney.client;

import com.beney.client.handler.ClientHandlerInitializer;
import com.beney.codec.MessagePacket;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;

@Component
public class Client {

    /**
     * 重连频率
     * TODO: 如何设置一个合理值
     */
    @Value("${netty.client.reconnect}")
    private Integer reconnectSec;

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Value("${netty.server.host}")
    private String serverHost;

    @Value("${netty.server.port}")
    private Integer serverPort;

    @Autowired
    private ClientHandlerInitializer clientHandlerInitializer;

    /**
     * 客户端只需要逻辑处理的线程组
     */
    private EventLoopGroup workerGroup = new NioEventLoopGroup();

    /**
     * 客户端 channel
     */
    private volatile Channel channel;

    /**
     * client 启动
     */
    @PostConstruct
    public void start() {
        Bootstrap b = new Bootstrap();
        b.group(workerGroup)
                .channel(NioSocketChannel.class)
                .remoteAddress(serverHost, serverPort)
//                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(clientHandlerInitializer);
        ChannelFuture future = b.connect();
        future.addListener((ChannelFutureListener) f -> {
            if (!f.isSuccess()) {
                logger.error("[start][Client 连接服务器 ({}:{}) 失败]", serverHost, serverPort);
                reconnect();
                return;
            }
            channel = f.channel();
            logger.info("[start][Client 连接服务器 ({}:{}) 成功]", serverHost, serverPort);
        });
    }

    /**
     * 关闭客户端
     */
    @PreDestroy
    public void shutdown() {
        if (channel != null) {
            channel.close();
        }
        workerGroup.shutdownGracefully();
    }

    /**
     * 重新连接
     */
    public void reconnect() {
        workerGroup.schedule(() -> {
            logger.info("[reconnect][客户端开始重连]");
            start();
        }, reconnectSec, TimeUnit.SECONDS);
        logger.info("[reconnect][{} 秒后重新发起连接...]", reconnectSec);
    }

    /**
     * 向服务端发送消息包
     *
     * @param messagePacket 消息包
     */
    public void send(MessagePacket messagePacket) {
        if (channel == null) {
            logger.error("[send][连接不存在]");
            return;
        }
        if (!channel.isActive()) {
            logger.error("[send][连接 ({}) 尚未活跃]", channel.id());
            return;
        }
        channel.writeAndFlush(messagePacket);
    }
}
